#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

cv::Mat get_laplacian_of_gaussian_kernel(int ksize, double sigma) {
    cv::Mat kernel(ksize, ksize, CV_32FC1);
    int center = ksize / 2;
    double hg = 0;
    for (int i = 0; i < ksize; i++) {
        float* p = kernel.ptr<float>(i);
        for (int j = 0; j < ksize; j++) {
            int x = j - center;
            int y = i - center;
            double h = std::exp(-(x*x + y*y) / (2.0*sigma*sigma));
            hg += h;
            p[j] = (x*x + y*y - 2*sigma*sigma) * h / (sigma*sigma*sigma*sigma);
        }
    }
    kernel /= hg;
    return kernel;
}

int main(int argc, char **argv) {
    cv::Mat mat = cv::imread("/home/xlll/Downloads/opencv/samples/data/lena.jpg", cv::IMREAD_GRAYSCALE);
    if (mat.empty()) {
        std::cout << "Failed to read image!" << std::endl;
        return EXIT_FAILURE;
    }
    
    int ksize = 11;
    double sigma = 1.5;
    cv::Mat gaussianMat, logMat;
    cv::GaussianBlur(mat, gaussianMat, cv::Size(ksize, ksize), sigma, sigma, cv::BORDER_REFLECT101);
    cv::Laplacian(gaussianMat, logMat, CV_8UC1, 1, 1.0, 0.0, cv::BORDER_REFLECT101);
    
    cv::Mat kernel = get_laplacian_of_gaussian_kernel(ksize, sigma);
    cv::Mat logMat2;
    cv::filter2D(mat, logMat2, CV_8UC1, kernel, cv::Point(-1, -1), 0.0, cv::BORDER_REFLECT101);
    
    cv::imshow("mat", mat);
    cv::imshow("gaussian", gaussianMat);
    cv::imshow("logMat", logMat);
    cv::imshow("logMat2", logMat2);
    
    cv::waitKey(0);
    return EXIT_SUCCESS;
}
